/*jslint vars: true, forin: true, sloppy: true */
/*global angular, ocDialog, DialogManager, DialogFactory */
ocDialog.provider('ocResizable', function () {
	// they can be configurable in the future
	var minWidth = 100,
		minHeight = 60;
	var border = 5;

	var RI, base, $document = angular.element(document);
	var topEdge, rightEdge, bottomEdge, leftEdge;
	var bound, x, y, newWidth, newHeight;
	var Resizable = function Resizable (options) {
		this.$element = null;
		this.element(options.element);

		this.$$style = this.$element[0].style;
	};

	Resizable.prototype.element = function (elm) {
		if(angular.isElement(elm)){
			this.$element = elm;
			elm.data("ResizableInstance", this);
			//cursor styling
			this.$element.on("mousemove", this.mousemovestyler);
			//handler
			this.$element.on("mousedown", this.mousedownhandler);
		}

		return this.$element;
	};

	Resizable.prototype.mousemovestyler = function (e) {
		RI = angular.element(this).data("ResizableInstance");
		RI.calcEdge(e);

		if(rightEdge && bottomEdge || leftEdge && topEdge){
			RI.$$style.cursor = 'nwse-resize';
		}
		else if(rightEdge && topEdge || leftEdge && bottomEdge){
			RI.$$style.cursor = 'nesw-resize';
		}
		else if(rightEdge || leftEdge){
			RI.$$style.cursor = 'ew-resize';
		}
		else if(topEdge || bottomEdge){
			RI.$$style.cursor = 'ns-resize';
		}
		else{
			RI.$$style.cursor = 'default';
		}
	};

	Resizable.prototype.mousedownhandler = function (e) {
		RI = angular.element(this).data("ResizableInstance");
		RI.calcEdge(e);

		e.preventDefault();

		//the user is in resize area, set the initial state
		if(topEdge || rightEdge || bottomEdge || leftEdge){
			base = {
				x: e.clientX + bound.width,
				y: e.clientY + bound.height,
				onTopEdge: topEdge,
				onRightEdge: rightEdge,
				onBottomEdge: bottomEdge,
				onLeftEdge: leftEdge
			};

			$document.on("mousemove", RI.mousemovehandler);
			$document.on("mouseup", RI.mouseuphandler);
		}
	};

	Resizable.prototype.mousemovehandler = function (e) {
		RI.calcEdge(e);

		if(base.onRightEdge){
			RI.$$style.width = Math.max(x, minWidth) + 'px';
		}

		if(base.onBottomEdge){
			RI.$$style.height = Math.max(y, minHeight) + 'px';
		}

		if(base.onLeftEdge){
			newWidth = base.x - e.clientX;
			if(newWidth >= minWidth){
				RI.$$style.width = newWidth + 'px';
				RI.$$style.left = e.clientX + 'px';
			}
		}

		if(base.onTopEdge){
			newHeight = base.y - e.clientY;
			if(newHeight >= minHeight){
				RI.$$style.height = newHeight + 'px';
				RI.$$style.top = e.clientY + 'px';
			}
		}
	};

	Resizable.prototype.mouseuphandler = function () {
		$document.off("mousemove", RI.mousemovehandler);
		$document.off("mouseup", RI.mouseuphandler);
	};

	Resizable.prototype.calcEdge = function (e) {
		bound = this.$element[0].getBoundingClientRect();
		x = e.clientX - bound.left;
		y = e.clientY - bound.top;

		topEdge = y < border;
		rightEdge = x >= bound.width - border;
		bottomEdge = y >= bound.height - border;
		leftEdge = x < border;
	};

	this.$get = function () {
		return {
			resizable: function (options) {
				return new Resizable(options);
			},
			isResizable: function (element) {
				return angular.isDefined(element.data("ResizableInstance"));
			}
		}
	};
});
